use std::fmt::{Display, Formatter};
use std::io::stdout;
use std::sync::Mutex;

use anyhow::anyhow;
use ftlog::appender::Period;
use ftlog::FtLogFormat;
use log::Record;

use crate::config::RootAppConfig;

/// # 选用 FtLog作为项目日志
/// 优势：
/// 1. 性能足够好，异步输出100_000耗时20ms左右
/// 2. 配置项组稿方便明了，去除了log4f的大部分不常用配置
/// 3. 兼容性客观
///

pub struct AppLogFormatter;

impl FtLogFormat for AppLogFormatter {
    fn msg(&self, record: &Record) -> Box<dyn Send + Sync + Display> {
        Box::new(format!(
            "{} {} [{}] ({}:{}) - {}",
            record.level(),
            std::thread::current().name().unwrap_or("<uname>"),
            record.module_path().unwrap(),
            record.file().unwrap(),
            record.line().unwrap(),
            record.args(),
        ))
    }
}
pub fn ftlog_init(app_config: &'static RootAppConfig) -> Result<(), Box<dyn std::error::Error>> {
    use ftlog::appender::*;
    use ftlog::LevelFilter;
    use ftlog::LevelFilter::*;
    const CONSOLE: &'static str = "console";
    let vec = app_config.log.as_ref().unwrap();
    let mut builder = ftlog::builder()
        .max_log_level(LevelFilter::Trace)
        .format(AppLogFormatter);
    assert!(vec.len() > 0, "check log");

    for log in vec {
        let appender = log.appender.as_ref().expect("check log.appender");
        let module = appender
            .module
            .as_ref()
            .expect("check log.appender.module")
            .as_str();
        let level = appender.level();
        let mut kind = appender.kind.as_ref().expect("check log.appender.kind");
        let root_log_flag = module.eq_ignore_ascii_case("Root");
        if let Some(file) = kind.file.as_ref() {
            let file_writer = FileAppender::rotate_with_expire(
                file.path
                    .as_ref()
                    .expect("check log.appender.kind.file.path"),
                file.period(),
                file.duration(),
            );
            if root_log_flag {
                builder = builder.root(file_writer).root_log_level(level)
            } else {
                builder = builder
                    .filter(module, module, level)
                    .appender(module, file_writer);
            }
        }
        if let Some(bl) = kind.console {
            if bl {
                if root_log_flag {
                    builder = builder.root(stdout()).root_log_level(level)
                } else {
                    builder = builder.filter(module, CONSOLE, level)
                }
            }
        };
    }
    builder.appender(CONSOLE, std::io::stdout()).try_init()
}
